import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';

import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:xvideos/hj_utils/api_service/vid_service.dart';
import 'package:xvideos/tools_base/debug_log.dart';
import 'package:xvideos/tools_base/file_upload/video_upload_result_model.dart';

import '../../config/address.dart';
import '../../hj_model/upload_video_model.dart';
import '../../hj_model/video_model.dart';
import '../../hj_utils/file_util.dart';
import '../../hj_utils/video_utils.dart';
import '../net/http_resp_interceptor.dart';
import '../net/net_manager.dart';
import 'image_upload_result_model.dart';

class FileUpLoadTool {
  int get maxImageSize => 200 * 1024;
  int get compressMaxCount => 5;
  int compressCount = 0;

  //生成表单数据
  FormData _generateFormData({required Uint8List data, String? fileName}) {
    return FormData.fromMap({
      'upload': MultipartFile.fromBytes(
        data,
        filename: fileName,
      ),
    });
  }

  _buildCommonOptions() async {
    return Options(
      method: "POST",
      sendTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(seconds: 30),
      contentType: "*/*",
      // 暂时让服务器全部接受
      headers: {
        'user-agent': await netManager.userAgent(),
        "Authorization": await netManager.getToken(),
      },
    );
  }

  Future<List<ImageUploadResultModel>?> uploadImageList(
    List<String> pathArr, {
    Function(int, int, int, int)? proCallback,
  }) async {
    List<ImageUploadResultModel> imageUrlArr = [];
    for (int i = 0; i < pathArr.length; i++) {
      dynamic path = pathArr[i];
      ImageUploadResultModel? model;
      model = await uploadImage(
        path,
        callback: (pro, total) {
          if (proCallback != null) {
            proCallback(i, pathArr.length, pro, total);
          }
        },
      );
      if (model?.coverImg?.isNotEmpty == true) {
        imageUrlArr.add(model!);
      } else {
        return null;
      }
    }
    return imageUrlArr;
  }

  //上传图片
  Future<ImageUploadResultModel?> uploadImage(String path, {Function(int, int)? callback}) async {
    var extent = FileUtil.getNameSuffix(path);
    var fileName = '${DateTime.now().toIso8601String()}_${Random().nextInt(1024)}.$extent';

    Uint8List fileData = File(path).readAsBytesSync();
    return uploadImageData(fileData, fileName: fileName, callback: callback);
  }

  Future<ImageUploadResultModel?> uploadImageData(
    Uint8List imageData, {
    String? fileName,
    int? maxSize,
    Function(int, int)? callback,
  }) async {
    Uint8List compressFileData = await compressImageList(
      imageData,
      maxSize: maxSize ?? maxImageSize,
      count: 2,
    );
    var name = fileName != null ? fileName : '${DateTime.now().toIso8601String()}_${Random().nextInt(1024)}.jpg';
    debugLog("开始上传----", fileName);
    FormData formData = _generateFormData(
      data: compressFileData,
      fileName: name,
    );

    var options = await _buildCommonOptions();
    ImageUploadResultModel? model;
    try {
      Dio dio = createDio();
      Response resp = await dio.post(
        "${Address.baseApiPath}${Address.UPLOAD_IMG}",
        options: options,
        data: formData,
        onSendProgress: (count, total) {
          if (callback != null) {
            callback(count, total);
          }
        },
      );
      if (resp.statusCode == 200) {
        await HttpRespInterceptor.handleResponse(resp);
        model = ImageUploadResultModel.fromMap(resp.data);
      } else {
        model = ImageUploadResultModel()..errorDesc = resp.statusMessage;
      }
    } catch (e) {
      debugLog("_uploadPatchOnce()...error:$e");
    }
    return model;
  }

  Future<VideoUploadResultModel?> uploadFile(
    String localPath, {
    Function(int, int, int, int)? proCallback,
  }) async {
    if (!FileUtil.isFileExist(localPath)) {
      return VideoUploadResultModel()..errorDesc = "视频文件找不到";
    }
    VideoUploadResultModel? retModel;
    try {
      File videoFile = File(localPath);
      int fileLen = FileUtil.getFileSize(localPath);
      Uint8List fileData = await videoFile.readAsBytes();
      List<int> bytes = fileData.buffer.asUint8List(fileData.offsetInBytes, fileData.lengthInBytes);
      String fileId = md5.convert(bytes).toString();
      // 1-n次，第n次可能不足一个分片
      int patchSize = FileUtil.getPatchSize(fileLen);
      int patchCount = FileUtil.getPatchCount(fileLen);
      debugLog("分段大小:$patchSize 视频被分成:$patchCount 个片段");

      for (int index = 0; index < patchCount; index++) {
        // 处理最后一个分片的长度
        int shouldReadLen = index < patchCount ? patchSize : min((fileLen) % patchSize, patchSize);
        Uint8List data = await FileUtil.getFileBlock(index * patchSize, shouldReadLen, videoFile);

        var options = Options(
          method: "POST",
          sendTimeout: const Duration(seconds: 30),
          receiveTimeout: const Duration(seconds: 60),
          contentType: "application/json",
          responseType: ResponseType.json,
          headers: {
            "Authorization": await netManager.getToken(),
            "User-Agent": await netManager.userAgent(),
            'Content-Type': 'application/json'
          },
        );

        var postData = {
          'data': base64.encode(data),
          'pos': index + 1,
          'totalPos': patchCount,
          'id': fileId,
        };
        Response resp = await createDio().post(
          Address.baseApiPath! + Address.UPLOAD_VIDEO,
          options: options,
          data: postData,
          onSendProgress: (count, total) {
            if (proCallback != null) {
              proCallback(index, patchCount, count, total);
            }
          },
        );
        await HttpRespInterceptor.handleResponse(resp);
        retModel = VideoUploadResultModel.fromMap(resp.data);
      }
      retModel?.md5 = fileId;
      return retModel;
    } catch (e) {
      retModel = VideoUploadResultModel()..errorDesc = e.toString();
    }
    return retModel;
  }

  Future<Uint8List> compressImageList(
    Uint8List list, {
    int maxSize = 200 * 1024,
    int count = 1,
  }) async {
    if (count == 0) return list;
    var result = await FlutterImageCompress.compressWithList(
      list,
      quality: 100,
      format: CompressFormat.jpeg,
    );
    debugLog("图片压缩原大小${list.length / 1024}, ${result.length / 1024}");
    compressCount++;
    if (result.length > maxSize && compressCount < compressMaxCount) {
      return compressImageList(result, maxSize: maxSize, count: count - 1);
    }
    return result;
  }

  Future<String> uploadVideoApi(UploadVideoModel uploadModel) async {
    dynamic pubRet;
    try {
      MediaInfo? mediaInfo = await VideoUtils.getMediaInfo(uploadModel.videoLocalPath ?? "");
      pubRet = await VidService.submitVideo(
          title: uploadModel.title,
          newsType: (uploadModel.seriesCover.isNotEmpty) ? NEWSTYPE_COVER_VIDEO : NEWSTYPE_VIDEO,
          sourceID: uploadModel.videoFileId,
          sourceURL: uploadModel.videoRemotePath,
          tags: uploadModel.selectedTagIdList,
          coins: uploadModel.coins,
          playTime: mediaInfo?.playTime,
          seriesCover: uploadModel.seriesCover,
          size: mediaInfo?.size,
          isActivity: uploadModel.isActivity,
          resolution: mediaInfo?.resolution,
          ratio: mediaInfo?.ratio ?? 0.0,
          actor: uploadModel.actor,
          filename: "${DateTime.now().toIso8601String()}.mp4",
          freeTime: uploadModel.freeTime,
          md5: uploadModel.fileMD5,
          mimeType: "mp4",
          via: Platform.operatingSystem,
          cover: uploadModel.coverRemotePath,
          coverThumb: uploadModel.coverRemotePath);
    } catch (e) {
      debugLog("uploadVideoApi()...error:$e");
    }
    if (pubRet is Map) {
      if (pubRet["data"] != 200) {
        return pubRet["msg"] ?? "";
      }
    }
    return "";
  }
}
